/**
 * @(#)SimulatorApkdownloadServiceImpl.java 2017年2月28日
 * Copyright(C) 2015 ZHEXIN IT CO.,LTD. All rights reserved.
 */
package org.jsbd.boss.service.impl;

import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

import javax.annotation.Resource;

import org.apache.commons.beanutils.BeanUtils;
import org.jsbd.boss.common.BusType;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.dao.IUserClientInfoDAO;
import org.jsbd.boss.domian.SimulatorADTask;
import org.jsbd.boss.domian.SimulatorUVConfig;
import org.jsbd.boss.domian.channel.QueryUserClientVo;
import org.jsbd.boss.domian.channel.UserClientInfo;
import org.jsbd.boss.service.ISimulatorADService;
import org.jsbd.boss.service.IUserAgentService;
import org.jsbd.boss.util.ADPoolExecutor;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DateUtil;
import org.jsbd.boss.util.NumUtil;
import org.jsbd.boss.util.PropertiesUtil;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zhexinit.proxy.domain.HttpContext;
import com.zhexinit.proxy.domain.HttpProxyLog;
import com.zhexinit.proxy.util.HttpProxyUtils;

import edu.hziee.common.queue.DelayExecuteBuffer;

/**
 * TODO 请加入本类的说明
 * 
 * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
 * @version 1.0.0
 */
@Service
public class SimulatorADServiceImpl implements ISimulatorADService {
	public static final Logger LOGGER = LoggerFactory.getLogger(SimulatorADServiceImpl.class);

	@Autowired
	private RedisClient redisClient;

	private static final int ONE_DAY = 60 * 60 * 24;
	@Autowired
	private DelayExecuteBuffer<HttpProxyLog> zxHttpProxyLogBuffer;

	@Resource
	private IUserAgentService userAgentService;

	@Resource
	private IUserClientInfoDAO userClientDao;

	private static String adUrL = "http://www.xxeden.com:8080/app/getAd?";

	private static String reportUrl = "http://www.xxeden.com:8080/app/reportParam?";

	private static Random r = new Random();

	private Integer clickratio = PropertiesUtil.getInt("simulator_ad_clickratio", 10);

	private static Set<Integer> provinceSet = new HashSet<>();

	@Override
	public void simulatorAD(final SimulatorUVConfig config) throws Exception {

		List<String> ualist = userAgentService.selectUserAgentList(config.getThreadnum());
		// 伪ua
		for (int i = 0; i < ualist.size(); i++) {
			UserClientInfo uclientInfo = selectUser(config);
			if (uclientInfo == null) {
				LOGGER.warn("can not find uclientInfo,uclientInfo is null.........");
				return;
			}
			String oldua = uclientInfo.getUserAgent();
			String build = oldua.substring(oldua.indexOf("("), oldua.indexOf(")") + 1);
			String newua = ualist.get(i);
			String nbuild = newua.substring(newua.indexOf("("), newua.indexOf(")") + 1);
			newua = newua.replaceAll(nbuild, build);
			uclientInfo.setUserAgent(newua);
			final SimulatorADTask task = new SimulatorADTask();
			copyBean(task, uclientInfo);
			int x = r.nextInt(task.getDvw());
			int y = r.nextInt(task.getDvh());
			task.setDownx(x);
			task.setDowny(y);
			task.setUpx(x);
			task.setUpy(y);

			FutureTask future = new FutureTask(new Callable<Boolean>() {
				public Boolean call() {
					String uvcountkey = getSuccessKey(config);
					try {
						redisClient.incrementBy(uvcountkey, 1, ONE_DAY);
						simulatorADTask(task);
						task.setPosition("4");
						int x = r.nextInt(task.getDvw());
						int y = r.nextInt(200);
						task.setDownx(x);
						task.setDowny(y);
						task.setUpx(x);
						task.setUpy(y);
						redisClient.putZset(CacheKey.YBAD_BANNER_DELAY_QUEUE, task, System.currentTimeMillis());
					} catch (Exception e) {
						LOGGER.error("InterruptedException: ", e);
					}
					return null;
				}

			});

			ADPoolExecutor.getPoolExeFuture(future);
		}

	}

	public String getSuccessKey(SimulatorUVConfig config) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cal = Calendar.getInstance();
		String date = df.format(cal.getTime());
		String id = config.getId();
		String uvcountkey = CacheKey.UV_TASK + id + "_" + date;
		return uvcountkey;
	}

	public Long getExeCount(SimulatorUVConfig config) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cal = Calendar.getInstance();
		String date = df.format(cal.getTime());
		String id = config.getId();
		String uvcountkey = CacheKey.UV_TASK + id + "_" + date;
		return redisClient.getLong(uvcountkey);
	}

	private void copyBean(SimulatorADTask task, UserClientInfo uclientInfo) {
		task.setAppkey("zhexing");
		task.setAppname("com.xxl3d.zx");
		task.setAppver("310");
		task.setPosition("2");
		task.setBrd(uclientInfo.getBoard());
		task.setCarrier("0");
		if (uclientInfo.getDensityDpi() == null) {
			task.setDensity(0);
		} else {
			task.setDensity(uclientInfo.getDensityDpi().intValue());
		}
		task.setDeviceid(uclientInfo.getImei());
		task.setDvh(uclientInfo.getScreenHeight());
		task.setDvw(uclientInfo.getScreenWidth());
		task.setImei(uclientInfo.getImei());
		task.setImsi(uclientInfo.getImsi());
		task.setLat(uclientInfo.getLatitude());
		task.setLon(uclientInfo.getLongitude());
		task.setMc(uclientInfo.getMac());
		task.setMd(uclientInfo.getHstype());
		task.setNt("wf");
		task.setOs("Android");
		String ovs = uclientInfo.getRelease();
		ovs = ovs.toLowerCase();
		if (ovs.indexOf("android") > -1) {
			task.setOvs(ovs);
		} else {
			task.setOvs("android " + ovs);
		}

		task.setUa(uclientInfo.getUserAgent());
	}

	public void simulatorADTask(SimulatorADTask task) {
		HttpContext httpContext = new HttpContext();
		httpContext.setOrderId(task.getImsi());
		httpContext.setProvinceId("-1");
		httpContext.setImsi(task.getImsi());
		httpContext.setBizType(BusType.AD_CHANNEL_GETADJSON.getMessage());

		HttpProxyLog httpProxyLog = new HttpProxyLog();
		httpProxyLog.getHeaderMap().putAll(getHeader(task));
		httpProxyLog.cloneAndSetHttpContext(httpContext);
		int pos = Integer.parseInt(task.getPosition());
		httpProxyLog.getHttpContext().setStep(BusType.AD_CHANNEL_GETADJSON.getCode() + pos);

		String adbody = getAD(httpProxyLog, task);
		if (adbody == null) {
			LOGGER.warn(" adbody is null,skip this ad");
			return;
		}
		JSONObject main = new JSONObject(adbody);
		JSONArray rspObjects = (JSONArray) main.get("rspObject");
		if (rspObjects == null || rspObjects.length() == 0) {
			LOGGER.warn(" rspObjects is null,skip this ad");
			return;
		}
		JSONObject rspObject = (JSONObject) rspObjects.get(0);
		String photo = rspObject.get("photo") + "";
		JSONArray imprs = ((JSONArray) rspObject.get("impr"));
		JSONArray clicks = ((JSONArray) rspObject.get("click"));
		String link = rspObject.get("link") + "";

		httpProxyLog.cloneAndSetHttpContext(httpContext);
		httpProxyLog.getHttpContext().setBizType(BusType.AD_CHANNEL_GETPHOTO.getMessage() + "-" + task.getPosition());
		httpProxyLog.getHttpContext().setStep(BusType.AD_CHANNEL_GETPHOTO.getCode());
		httpProxyLog.setUrl(photo);
		getphoto(httpProxyLog);

		for (int i = 0; i < imprs.length(); i++) {
			String impr = imprs.getString(i);
			httpProxyLog.cloneAndSetHttpContext(httpContext);
			httpProxyLog.getHttpContext().setBizType(BusType.AD_CHANNEL_GETIMPR.getMessage() + "-" + i);
			httpProxyLog.getHttpContext().setStep(BusType.AD_CHANNEL_GETIMPR.getCode());
			httpProxyLog.setUrl(impr);
			getimpr(httpProxyLog);
		}

		httpProxyLog.cloneAndSetHttpContext(httpContext);
		httpProxyLog.getHttpContext().setBizType(BusType.AD_CHANNEL_GETREPORTSHOW.getMessage() + "-" + task.getPosition());
		httpProxyLog.getHttpContext().setStep(BusType.AD_CHANNEL_GETREPORTSHOW.getCode());
		getreportshow(httpProxyLog, task, "1");

		int index = new Random().nextInt(100);
		if (index <= clickratio) {
			httpProxyLog.cloneAndSetHttpContext(httpContext);
			httpProxyLog.getHttpContext().setBizType(BusType.AD_CHANNEL_GETREPORTCLICK.getMessage() + "-" + task.getPosition());
			httpProxyLog.getHttpContext().setStep(BusType.AD_CHANNEL_GETREPORTCLICK.getCode());
			getreportclick(httpProxyLog, task, "2");
			getlink(httpProxyLog, httpContext, link);
			for (int i = 0; i < clicks.length(); i++) {
				String click = clicks.getString(i);
				getClick(httpProxyLog, httpContext, click);
			}
		}

	}

	/**
	 * 
	 * 1先到xxeden.com上去广告 2、get photo 3、get impr 4、get report 5、算概率，get link，再get
	 * click
	 */
	private String getAD(HttpProxyLog httpProxyLog1, SimulatorADTask task) {
		HttpProxyLog httpProxyLog = new HttpProxyLog();
		try {
			BeanUtils.copyProperties(httpProxyLog, httpProxyLog1);
		} catch (IllegalAccessException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		} catch (InvocationTargetException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		}
		String url = adUrL + getADParam(task);
		httpProxyLog.setUrl(url);
		String body = HttpProxyUtils.httpGet(httpProxyLog, zxHttpProxyLogBuffer, redisClient);
		return body;
	}

	private void getphoto(HttpProxyLog httpProxyLog1) {
		HttpProxyLog httpProxyLog = new HttpProxyLog();
		try {
			BeanUtils.copyProperties(httpProxyLog, httpProxyLog1);
		} catch (IllegalAccessException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		} catch (InvocationTargetException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		}
		HttpProxyUtils.httpDownload(httpProxyLog, zxHttpProxyLogBuffer, redisClient);
	}

	private String getimpr(HttpProxyLog httpProxyLog1) {
		HttpProxyLog httpProxyLog = new HttpProxyLog();
		try {
			BeanUtils.copyProperties(httpProxyLog, httpProxyLog1);
		} catch (IllegalAccessException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		} catch (InvocationTargetException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		}
		String body = HttpProxyUtils.httpGet(httpProxyLog, zxHttpProxyLogBuffer, redisClient);
		return body;
	}

	private String getreportshow(HttpProxyLog httpProxyLog1, SimulatorADTask task, String type) {
		HttpProxyLog httpProxyLog = new HttpProxyLog();
		try {
			BeanUtils.copyProperties(httpProxyLog, httpProxyLog1);
		} catch (IllegalAccessException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		} catch (InvocationTargetException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		}
		String url = reportUrl + getADParam(task) + "&type=" + type;
		httpProxyLog.setUrl(url);
		String body = HttpProxyUtils.httpGet(httpProxyLog, zxHttpProxyLogBuffer, redisClient);
		return body;
	}

	private String getreportclick(HttpProxyLog httpProxyLog1, SimulatorADTask task, String type) {
		HttpProxyLog httpProxyLog = new HttpProxyLog();
		try {
			BeanUtils.copyProperties(httpProxyLog, httpProxyLog1);
		} catch (IllegalAccessException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		} catch (InvocationTargetException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		}
		String url = reportUrl + getReportParam(task) + "&type=" + type;
		httpProxyLog.setUrl(url);
		String body = HttpProxyUtils.httpGet(httpProxyLog, zxHttpProxyLogBuffer, redisClient);
		return body;
	}

	private String getlink(HttpProxyLog httpProxyLog1, HttpContext httpContext, String link) {

		httpProxyLog1.cloneAndSetHttpContext(httpContext);
		httpProxyLog1.getHttpContext().setBizType(BusType.AD_CHANNEL_GETLINK.getMessage());
		httpProxyLog1.getHttpContext().setStep(BusType.AD_CHANNEL_GETLINK.getCode());
		httpProxyLog1.setUrl(link);

		HttpProxyLog httpProxyLog = new HttpProxyLog();
		try {
			BeanUtils.copyProperties(httpProxyLog, httpProxyLog1);
		} catch (IllegalAccessException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		} catch (InvocationTargetException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		}
		String body = HttpProxyUtils.httpGet(httpProxyLog, zxHttpProxyLogBuffer, redisClient);
		return body;
	}

	private String getClick(HttpProxyLog httpProxyLog1, HttpContext httpContext, String click) {

		httpProxyLog1.cloneAndSetHttpContext(httpContext);
		httpProxyLog1.getHttpContext().setBizType(BusType.AD_CHANNEL_GETCLICK.getMessage());
		httpProxyLog1.getHttpContext().setStep(BusType.AD_CHANNEL_GETCLICK.getCode());
		httpProxyLog1.setUrl(click);
		HttpProxyLog httpProxyLog2 = new HttpProxyLog();
		try {
			BeanUtils.copyProperties(httpProxyLog2, httpProxyLog1);
		} catch (IllegalAccessException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		} catch (InvocationTargetException e) {
			LOGGER.warn("Any warn msg that u want to write", e);
		}
		String body = HttpProxyUtils.httpGet(httpProxyLog2, zxHttpProxyLogBuffer, redisClient);
		return body;
	}

	private void getParam(Map<String, Object> map, SimulatorADTask task) {

		map.put("appkey", task.getAppkey());
		map.put("appname", task.getAppname());
		map.put("appver", task.getAppver());
		map.put("position", task.getPosition());
		map.put("adType", task.getPosition());
		map.put("brd", task.getBrd());
		map.put("carrier", task.getCarrier());
		map.put("density", task.getDensity());
		map.put("imei", task.getImei());
		map.put("imsi", task.getImsi());
		map.put("mc", task.getMc());
		map.put("md", task.getMd());
		map.put("dvh", task.getDvh());
		map.put("dvw", task.getDvw());
		map.put("nt", task.getNt());
		map.put("os", task.getOs());
		map.put("ovs", task.getOvs());
		map.put("deviceid", task.getDeviceid());
		map.put("ua", task.getUa());
	}

	private String getReportParam(SimulatorADTask task) {
		Map<String, Object> map = new HashMap<String, Object>();
		String param = "";
		getParam(map, task);
		map.put("down_x", task.getDownx());
		map.put("down_y", task.getDowny());
		map.put("up_x", task.getUpx());
		map.put("up_y", task.getUpy());
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			param += entry.getKey() + "=" + java.net.URLEncoder.encode(entry.getValue() + "") + "&";
		}
		return param.substring(0, param.length() - 1);
	}

	private String getADParam(SimulatorADTask task) {
		Map<String, Object> map = new HashMap<String, Object>();
		String param = "";
		getParam(map, task);
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			param += entry.getKey() + "=" + java.net.URLEncoder.encode(entry.getValue() + "") + "&";
		}
		return param.substring(0, param.length() - 1);
	}

	private HttpProxyLog getHttpProxyLog(SimulatorADTask task) {
		HttpProxyLog result = new HttpProxyLog();

		return result;
	}

	public Map<String, String> getHeader(SimulatorADTask task) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp, */*");
		map.put("Accept-Language", "en-US,en;q=0.8,zh-CN;q=0.6,zh");
		map.put("Accept-Encoding", "gzip, deflate");
		map.put("User-Agent", task.getUa());
		map.put("Connection", " keep-alive");
		map.put("Upgrade-Insecure-Requests", "1");
		map.put("Cache-Control", "no-cache");
		map.put("Pragma", "no-cache");
		return map;
	}

	private UserClientInfo selectUser(SimulatorUVConfig config) {
		for (int i = 0; i < 31; i++) {
			provinceSet.add(i);
		}
		Integer[] provinces = provinceSet.toArray(new Integer[0]);
		provinces = NumUtil.randomNums(provinces);
		for (int j = 0; j < provinces.length; j++) {
			int provinceId = provinces[j];
			QueryUserClientVo userVo = new QueryUserClientVo();
			userVo.setProvince(provinceId);
			userVo.setLength(100);
			String indexKey = CacheKey.QBAD_LOGIN_APK + provinceId + config.getId() + DateUtil.getCurrentDateStr();
			String qKey = CacheKey.QBAD_USER_QUEUE + provinceId + config.getId();
			Long start = 0L;
			Object loginIndex = redisClient.get(indexKey);
			if (loginIndex != null) {
				start = Long.parseLong(loginIndex.toString());
			}
			userVo.setId(start);
			UserClientInfo userObj = (UserClientInfo) redisClient.pollFromQueue(qKey);
			if (userObj != null) {
				return userObj;
			} else {
				long expireTime = 10;
				if (redisClient.evalSetNx(qKey + "_LOCK", expireTime)) {
					List<UserClientInfo> userList = userClientDao.selectRandomClientList(userVo);
					if (userList != null && userList.size() > 0) {
						for (int i = 0; i < userList.size(); i++) {
							UserClientInfo user = userList.get(i);
							if (i > 0) {
								redisClient.putToQueue(qKey, user);
							}
							if (start < user.getId()) {
								start = user.getId();
							}
						}
						redisClient.put(indexKey, start);
						return userList.get(0);
					} else {

					}
				}
			}
		}
		return null;
	}

}
